home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / advanced97 / PROJTEX.C < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  19.9 KB  |  839 lines

  1. /*
  2. ** Demonstrates simple projective texture mapping.
  3. **
  4. ** Button1 changes view, Button2 moves texture.
  5. **
  6. ** (See: Segal, Korobkin, van Widenfelt, Foran, and Haeberli
  7. **  "Fast Shadows and Lighting Effects Using Texture Mapping", SIGGRAPH    '92)
  8. **
  9. ** 1994,1995 -- David G Yu
  10. **
  11. ** cc -o projtex projtex.c texture.c -lglut -lGLU -lGL -lX11 -lm
  12. */
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <math.h>
  16. #include <GL/glut.h>
  17. #include "texture.h"
  18.  
  19. /* Some <math.h> files do not define M_PI... */
  20. #ifndef M_PI
  21. #define M_PI 3.14159265358979323846
  22. #endif
  23.  
  24. int winWidth, winHeight;
  25.  
  26. GLboolean redrawContinuously;
  27.  
  28. float angle, axis[3];
  29. enum MoveModes { MoveNone, MoveView, MoveObject, MoveTexture };
  30. enum MoveModes mode = MoveNone;
  31.  
  32. GLfloat objectXform[4][4];
  33. GLfloat textureXform[4][4];
  34.  
  35. void (*drawObject)(void);
  36. void (*loadTexture)(void);
  37. GLboolean textureEnabled = GL_TRUE;
  38. GLboolean showProjection = GL_TRUE;
  39. GLboolean linearFilter = GL_TRUE;
  40.  
  41. char *texFilename = NULL;
  42.  
  43. GLfloat zoomFactor = 1.0;
  44.  
  45. /*****************************************************************/
  46.  
  47. /* matrix = identity */
  48. void
  49. matrixIdentity(GLfloat matrix[16])
  50. {
  51.     matrix[ 0] = 1.0;
  52.     matrix[ 1] = 0.0;
  53.     matrix[ 2] = 0.0;
  54.     matrix[ 3] = 0.0;
  55.     matrix[ 4] = 0.0;
  56.     matrix[ 5] = 1.0;
  57.     matrix[ 6] = 0.0;
  58.     matrix[ 7] = 0.0;
  59.     matrix[ 8] = 0.0;
  60.     matrix[ 9] = 0.0;
  61.     matrix[10] = 1.0;
  62.     matrix[11] = 0.0;
  63.     matrix[12] = 0.0;
  64.     matrix[13] = 0.0;
  65.     matrix[14] = 0.0;
  66.     matrix[15] = 1.0;
  67. }
  68.  
  69. /* matrix2 = transpose(matrix1) */
  70. void
  71. matrixTranspose(GLfloat matrix2[16], GLfloat matrix1[16])
  72. {
  73.     matrix2[ 0] = matrix1[ 0];
  74.     matrix2[ 1] = matrix1[ 4];
  75.     matrix2[ 2] = matrix1[ 8];
  76.     matrix2[ 3] = matrix1[12];
  77.  
  78.     matrix2[ 4] = matrix1[ 1];
  79.     matrix2[ 5] = matrix1[ 5];
  80.     matrix2[ 6] = matrix1[ 9];
  81.     matrix2[ 7] = matrix1[13];
  82.  
  83.     matrix2[ 8] = matrix1[ 2];
  84.     matrix2[ 9] = matrix1[ 6];
  85.     matrix2[10] = matrix1[10];
  86.     matrix2[11] = matrix1[14];
  87.  
  88.     matrix2[12] = matrix1[ 3];
  89.     matrix2[13] = matrix1[ 7];
  90.     matrix2[14] = matrix1[14];
  91.     matrix2[15] = matrix1[15];
  92. }
  93.  
  94. /*****************************************************************/
  95.  
  96. /* load SGI .rgb image (pad with a border of the specified width and color) */
  97. static void
  98. imgLoad(char *filenameIn, int borderIn, GLfloat borderColorIn[4],
  99.     int *wOut, int *hOut, GLubyte **imgOut)
  100. {
  101.     int border = borderIn;
  102.     int width, height;
  103.     int w, h;
  104.     GLubyte *image, *img, *p;
  105.     int i, j, components;
  106.  
  107.     image = (GLubyte *)read_texture(filenameIn, &width, &height, &components);
  108.     w = width + 2*border;
  109.     h = height + 2*border;
  110.     img = (GLubyte *) calloc(w*h, 4*sizeof(unsigned char));
  111.  
  112.     p = img;
  113.     for (j=-border; j<height+border; ++j) {
  114.     for (i=-border; i<width+border; ++i) {
  115.         if (0 <= j && j <= height-1 && 0 <= i && i <= width-1) {
  116.         p[0] = image[4*(j*width+i)+0];
  117.         p[1] = image[4*(j*width+i)+1];
  118.         p[2] = image[4*(j*width+i)+2];
  119.         p[3] = 0xff;
  120.         } else {
  121.         p[0] = borderColorIn[0] * 0xff;
  122.         p[1] = borderColorIn[1] * 0xff;
  123.         p[2] = borderColorIn[2] * 0xff;
  124.         p[3] = borderColorIn[3] * 0xff;
  125.         }
  126.         p += 4;
  127.     }
  128.     }
  129.     free(image);
  130.     *wOut = w;
  131.     *hOut = h;
  132.     *imgOut = img;
  133. }
  134.  
  135. /*****************************************************************/
  136.  
  137. /* Load the image file specified on the command line as the current texture */
  138. void
  139. loadImageTexture(void)
  140. {
  141.     static int texWidth, texHeight;
  142.     static GLubyte *texData; 
  143.     GLfloat borderColor[4] = { 1.0, 1.0, 1.0, 1.0 };
  144.  
  145.     if (!texData) {
  146.     imgLoad(texFilename, 2, borderColor, &texWidth, &texHeight, &texData);
  147.     }
  148.  
  149.     if (linearFilter) {
  150.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  151.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  152.     } else {
  153.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  154.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  155.     }
  156.     glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
  157.     gluBuild2DMipmaps(GL_TEXTURE_2D, 4, texWidth, texHeight,
  158.               GL_RGBA, GL_UNSIGNED_BYTE, texData);
  159. }
  160.  
  161. /* Create a simple spotlight pattern and make it the current texture */
  162. void
  163. loadSpotlightTexture(void)
  164. {
  165.     static int texWidth = 64, texHeight = 64;
  166.     static GLubyte *texData; 
  167.     GLfloat borderColor[4] = { 0.1, 0.1, 0.1, 1.0 };
  168.  
  169.     if (!texData) {
  170.     GLubyte *p;
  171.     int i, j;
  172.  
  173.     texData = (GLubyte *) malloc(texWidth*texHeight*4*sizeof(GLubyte));
  174.  
  175.     p = texData;
  176.     for (j=0; j<texHeight; ++j) {
  177.         float dy = (texHeight*0.5 - j+0.5) / (texHeight*0.5);
  178.  
  179.         for (i=0; i<texWidth; ++i) {
  180.         float dx = (texWidth*0.5 - i+0.5) / (texWidth*0.5);
  181.         float r = cos(M_PI/2.0 * sqrt(dx*dx +dy*dy));
  182.         float c;
  183.  
  184.         r = (r < 0) ? 0 : r*r;
  185.         c = 0xff * (r + borderColor[0]);
  186.         p[0] = (c <= 0xff) ? c : 0xff;
  187.         c = 0xff * (r + borderColor[1]);
  188.         p[1] = (c <= 0xff) ? c : 0xff;
  189.         c = 0xff * (r + borderColor[2]);
  190.         p[2] = (c <= 0xff) ? c : 0xff;
  191.         c = 0xff * (r + borderColor[3]);
  192.         p[3] = (c <= 0xff) ? c : 0xff;
  193.         p += 4;
  194.         }
  195.     }
  196.     }
  197.  
  198.     if (linearFilter) {
  199.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  200.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  201.     } else {
  202.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  203.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  204.     }
  205.     glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
  206.     gluBuild2DMipmaps(GL_TEXTURE_2D, 4, texWidth, texHeight,
  207.               GL_RGBA, GL_UNSIGNED_BYTE, texData);
  208. }
  209.  
  210. /*****************************************************************/
  211.  
  212. void
  213. checkErrors(void)
  214. {
  215.     GLenum error;
  216.     while ((error = glGetError()) != GL_NO_ERROR) {
  217.     fprintf(stderr, "Error: %s\n", (char *) gluErrorString(error));
  218.     }
  219. }
  220.  
  221. void
  222. drawCube(void)
  223. {
  224.     glBegin(GL_QUADS);
  225.  
  226.     glNormal3f(-1.0, 0.0, 0.0 );
  227.     glColor3f(0.80, 0.50, 0.50);
  228.     glVertex3f(-0.5,-0.5,-0.5 ); glVertex3f(-0.5,-0.5, 0.5 );
  229.     glVertex3f(-0.5, 0.5, 0.5 ); glVertex3f(-0.5, 0.5,-0.5 );
  230.  
  231.     glNormal3f( 1.0, 0.0, 0.0 );
  232.     glColor3f(0.50, 0.80, 0.50);
  233.     glVertex3f( 0.5, 0.5, 0.5 ); glVertex3f( 0.5,-0.5, 0.5 );
  234.     glVertex3f( 0.5,-0.5,-0.5 ); glVertex3f( 0.5, 0.5,-0.5 );
  235.  
  236.     glNormal3f( 0.0,-1.0, 0.0 );
  237.     glColor3f(0.50, 0.50, 0.80);
  238.     glVertex3f(-0.5,-0.5,-0.5 ); glVertex3f( 0.5,-0.5,-0.5 );
  239.     glVertex3f( 0.5,-0.5, 0.5 ); glVertex3f(-0.5,-0.5, 0.5 );
  240.  
  241.     glNormal3f( 0.0, 1.0, 0.0 );
  242.     glColor3f(0.50, 0.80, 0.80);
  243.     glVertex3f( 0.5, 0.5, 0.5 ); glVertex3f( 0.5, 0.5,-0.5 );
  244.     glVertex3f(-0.5, 0.5,-0.5 ); glVertex3f(-0.5, 0.5, 0.5 );
  245.  
  246.     glNormal3f( 0.0, 0.0,-1.0 );
  247.     glColor3f(0.80, 0.50, 0.80);
  248.     glVertex3f(-0.5,-0.5,-0.5 ); glVertex3f(-0.5, 0.5,-0.5 );
  249.     glVertex3f( 0.5, 0.5,-0.5 ); glVertex3f( 0.5,-0.5,-0.5 );
  250.  
  251.     glNormal3f( 0.0, 0.0, 1.0 );
  252.     glColor3f(1.00, 0.80, 0.50);
  253.     glVertex3f( 0.5, 0.5, 0.5 ); glVertex3f(-0.5, 0.5, 0.5 );
  254.     glVertex3f(-0.5,-0.5, 0.5 ); glVertex3f( 0.5,-0.5, 0.5 );
  255.     glEnd();
  256. }
  257.  
  258. void
  259. drawDodecahedron(void)
  260. {
  261. #define A (0.5 * 1.61803)    /* (sqrt(5) + 1) / 2 */
  262. #define B (0.5 * 0.61803)    /* (sqrt(5) - 1) / 2 */
  263. #define C (0.5 * 1.0)
  264.     GLfloat vertexes[20][3] = {
  265.     {-A, 0.0, B }, {-A, 0.0,-B }, { A, 0.0,-B }, { A, 0.0, B },
  266.     { B,-A, 0.0 }, {-B,-A, 0.0 }, {-B, A, 0.0 }, { B, A, 0.0 },
  267.     { 0.0, B,-A }, { 0.0,-B,-A }, { 0.0,-B, A }, { 0.0, B, A },
  268.     {-C,-C, C }, {-C,-C,-C }, { C,-C,-C }, { C,-C, C },
  269.     {-C, C, C }, {-C, C,-C }, { C, C,-C }, { C, C, C },
  270.     };
  271. #undef A
  272. #undef B
  273. #undef C
  274.     GLint polygons[12][5] = {
  275.     {  0, 12, 10, 11, 16 },
  276.     {  1, 17,  8,  9, 13 },
  277.     {  2, 14,  9,  8, 18 },
  278.     {  3, 19, 11, 10, 15 },
  279.     {  4, 14,  2,  3, 15 },
  280.     {  5, 12,  0,  1, 13 },
  281.     {  6, 17,  1,  0, 16 },
  282.     {  7, 19,  3,  2, 18 },
  283.     {  8, 17,  6,  7, 18 },
  284.     {  9, 14,  4,  5, 13 },
  285.     { 10, 12,  5,  4, 15 },
  286.     { 11, 19,  7,  6, 16 },
  287.     };
  288.     int i;
  289.  
  290.     glColor3f(0.75, 0.75, 0.75);
  291.     for (i=0; i<12; ++i) {
  292.     GLfloat *p0, *p1, *p2, d;
  293.     GLfloat u[3], v[3], n[3];
  294.  
  295.     p0 = &vertexes[polygons[i][0]][0];
  296.     p1 = &vertexes[polygons[i][1]][0];
  297.     p2 = &vertexes[polygons[i][2]][0];
  298.  
  299.     u[0] = p2[0] - p1[0];
  300.     u[1] = p2[1] - p1[1];
  301.     u[2] = p2[2] - p1[2];
  302.  
  303.     v[0] = p0[0] - p1[0];
  304.     v[1] = p0[1] - p1[1];
  305.     v[2] = p0[2] - p1[2];
  306.  
  307.     n[0] = u[1]*v[2] - u[2]*v[1];
  308.     n[1] = u[2]*v[0] - u[0]*v[2];
  309.     n[2] = u[0]*v[1] - u[1]*v[0];
  310.  
  311.     d = 1.0 / sqrt(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]);
  312.     n[0] *= d;
  313.     n[1] *= d;
  314.     n[2] *= d;
  315.  
  316.     glBegin(GL_POLYGON);
  317.     glNormal3fv(n);
  318.     glVertex3fv(p0);
  319.     glVertex3fv(p1);
  320.     glVertex3fv(p2);
  321.     glVertex3fv(vertexes[polygons[i][3]]);
  322.     glVertex3fv(vertexes[polygons[i][4]]);
  323.     glEnd();
  324.     }
  325. }
  326.  
  327. void
  328. drawSphere(void)
  329. {
  330.     int numMajor = 24;
  331.     int numMinor = 32;
  332.     float radius = 0.8;
  333.     double majorStep = (M_PI / numMajor);
  334.     double minorStep = (2.0*M_PI / numMinor);
  335.     int i, j;
  336.  
  337.     glColor3f(0.50, 0.50, 0.50);
  338.     for (i=0; i<numMajor; ++i) {
  339.     double a = i * majorStep;
  340.     double b = a + majorStep;
  341.     double r0 = radius * sin(a);
  342.     double r1 = radius * sin(b);
  343.     GLfloat z0 = radius * cos(a);
  344.     GLfloat z1 = radius * cos(b);
  345.  
  346.     glBegin(GL_TRIANGLE_STRIP);
  347.     for (j=0; j<=numMinor; ++j) {
  348.         double c = j * minorStep;
  349.         GLfloat x = cos(c);
  350.         GLfloat y = sin(c);
  351.  
  352.         glNormal3f((x*r0)/radius, (y*r0)/radius, z0/radius);
  353.         glTexCoord2f(j/(GLfloat) numMinor, i/(GLfloat) numMajor);
  354.         glVertex3f(x*r0, y*r0, z0);
  355.  
  356.         glNormal3f((x*r1)/radius, (y*r1)/radius, z1/radius);
  357.         glTexCoord2f(j/(GLfloat) numMinor, (i+1)/(GLfloat) numMajor);
  358.         glVertex3f(x*r1, y*r1, z1);
  359.     }
  360.     glEnd();
  361.     }
  362. }
  363.  
  364. /*****************************************************************/
  365.  
  366. float xmin = -0.035, xmax = 0.035;
  367. float ymin = -0.035, ymax = 0.035;
  368. float znear = 0.1;
  369. float zfar = 1.9;
  370. float distance = -1.0;
  371.  
  372. static void
  373. loadTextureProjection(GLfloat m[16])
  374. {
  375.     GLfloat mInverse[4][4];
  376.  
  377.     /*
  378.     ** Should use true inverse, but since m consists only
  379.     ** of rotations, we can just use the transpose.
  380.     */
  381.     matrixTranspose((GLfloat *) mInverse, m);
  382.  
  383.     glMatrixMode(GL_TEXTURE);
  384.     glLoadIdentity();
  385.     glTranslatef(0.5, 0.5, 0.0);
  386.     glScalef(0.5, 0.5, 1.0);
  387.     glFrustum(xmin, xmax, ymin, ymax, znear, zfar);
  388.     glTranslatef(0.0, 0.0, distance);
  389.     glMultMatrixf((GLfloat *) mInverse);
  390.     glMatrixMode(GL_MODELVIEW);
  391. }
  392.  
  393. static void
  394. drawTextureProjection(void)
  395. {
  396.     float t = zfar / znear;
  397.     GLfloat n[4][3];
  398.     GLfloat f[4][3];
  399.  
  400.     n[0][0] = xmin;
  401.     n[0][1] = ymin;
  402.     n[0][2] = -(znear + distance);
  403.  
  404.     n[1][0] = xmax;
  405.     n[1][1] = ymin;
  406.     n[1][2] = -(znear + distance);
  407.  
  408.     n[2][0] = xmax;
  409.     n[2][1] = ymax;
  410.     n[2][2] = -(znear + distance);
  411.  
  412.     n[3][0] = xmin;
  413.     n[3][1] = ymax;
  414.     n[3][2] = -(znear + distance);
  415.  
  416.     f[0][0] = xmin * t;
  417.     f[0][1] = ymin * t;
  418.     f[0][2] = -(zfar + distance);
  419.  
  420.     f[1][0] = xmax * t;
  421.     f[1][1] = ymin * t;
  422.     f[1][2] = -(zfar + distance);
  423.  
  424.     f[2][0] = xmax * t;
  425.     f[2][1] = ymax * t;
  426.     f[2][2] = -(zfar + distance);
  427.  
  428.     f[3][0] = xmin * t;
  429.     f[3][1] = ymax * t;
  430.     f[3][2] = -(zfar + distance);
  431.  
  432.     glColor3f(1.0, 1.0, 0.0);
  433.     glBegin(GL_LINE_LOOP);
  434.       glVertex3fv(n[0]);
  435.       glVertex3fv(n[1]);
  436.       glVertex3fv(n[2]);
  437.       glVertex3fv(n[3]);
  438.       glVertex3fv(f[3]);
  439.       glVertex3fv(f[2]);
  440.       glVertex3fv(f[1]);
  441.       glVertex3fv(f[0]);
  442.       glVertex3fv(n[0]);
  443.       glVertex3fv(n[1]);
  444.       glVertex3fv(f[1]);
  445.       glVertex3fv(f[0]);
  446.       glVertex3fv(f[3]);
  447.       glVertex3fv(f[2]);
  448.       glVertex3fv(n[2]);
  449.       glVertex3fv(n[3]);
  450.     glEnd();
  451. }
  452.  
  453. /*****************************************************************/
  454.  
  455. void
  456. initialize(void)
  457. {
  458.     GLfloat light0Pos[4] = { 0.3, 0.3, 0.0, 1.0 };
  459.     GLfloat matAmb[4] = { 0.01, 0.01, 0.01, 1.00 };
  460.     GLfloat matDiff[4] = { 0.65, 0.65, 0.65, 1.00 };
  461.     GLfloat matSpec[4] = { 0.30, 0.30, 0.30, 1.00 };
  462.     GLfloat matShine = 10.0;
  463.     GLfloat eyePlaneS[] = { 1.0, 0.0, 0.0, 0.0 };
  464.     GLfloat eyePlaneT[] = { 0.0, 1.0, 0.0, 0.0 };
  465.     GLfloat eyePlaneR[] = { 0.0, 0.0, 1.0, 0.0 };
  466.     GLfloat eyePlaneQ[] = { 0.0, 0.0, 0.0, 1.0 };
  467.  
  468.     /*
  469.     ** Setup Misc.
  470.     */
  471.     glClearColor(0.41, 0.41, 0.31, 0.0);
  472.  
  473.     glEnable(GL_DEPTH_TEST);
  474.  
  475.     glLineWidth(2.0);
  476.  
  477.     glCullFace(GL_FRONT);
  478.     glEnable(GL_CULL_FACE);
  479.  
  480.     glMatrixMode(GL_PROJECTION);
  481.     glFrustum(-0.5, 0.5, -0.5, 0.5, 1, 3);
  482.     glMatrixMode(GL_MODELVIEW);
  483.     glTranslatef(0, 0, -2);
  484.  
  485.     matrixIdentity((GLfloat *) objectXform);
  486.     matrixIdentity((GLfloat *) textureXform);
  487.  
  488.     glMatrixMode(GL_PROJECTION);
  489.     glPushMatrix();
  490.     glLoadIdentity();
  491.     glOrtho(0, 1, 0, 1, -1, 1);
  492.     glMatrixMode(GL_MODELVIEW);
  493.     glPushMatrix();
  494.     glLoadIdentity();
  495.  
  496.     glRasterPos2i(0, 0);
  497.  
  498.     glPopMatrix();
  499.     glMatrixMode(GL_PROJECTION);
  500.     glPopMatrix();
  501.     glMatrixMode(GL_MODELVIEW);
  502.  
  503.     /*
  504.     ** Setup Lighting
  505.     */
  506.     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, matAmb);
  507.     glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, matDiff);
  508.     glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, matSpec);
  509.     glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, matShine);
  510.  
  511.     glEnable(GL_COLOR_MATERIAL);
  512.  
  513.     glLightfv(GL_LIGHT0, GL_POSITION, light0Pos);
  514.     glEnable(GL_LIGHT0);
  515.  
  516.     glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
  517.     glEnable(GL_LIGHTING);
  518.  
  519.     /*
  520.     ** Setup Texture
  521.     */
  522.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  523.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  524.     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  525.     (*loadTexture)();
  526.  
  527.     glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
  528.     glTexGenfv(GL_S, GL_EYE_PLANE, eyePlaneS);
  529.  
  530.     glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
  531.     glTexGenfv(GL_T, GL_EYE_PLANE, eyePlaneT);
  532.  
  533.     glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
  534.     glTexGenfv(GL_R, GL_EYE_PLANE, eyePlaneR);
  535.  
  536.     glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
  537.     glTexGenfv(GL_Q, GL_EYE_PLANE, eyePlaneQ);
  538. }
  539.  
  540. void
  541. display(void)
  542. {
  543.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  544.  
  545.     if (textureEnabled) {
  546.     if (mode == MoveTexture || mode == MoveView) {
  547.         /* Have OpenGL compute the new transformation (simple but slow). */
  548.         glPushMatrix();
  549.         glLoadIdentity();
  550.         glRotatef(angle, axis[0], axis[1], axis[2]);
  551.         glMultMatrixf((GLfloat *) textureXform);
  552.         glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *) textureXform);
  553.         glPopMatrix();
  554.     }
  555.  
  556.     loadTextureProjection((GLfloat *) textureXform);
  557.  
  558.     if (showProjection) {
  559.         glPushMatrix();
  560.         glMultMatrixf((GLfloat *) textureXform);
  561.         glDisable(GL_LIGHTING);
  562.         drawTextureProjection();
  563.         glEnable(GL_LIGHTING);
  564.         glPopMatrix();
  565.     }
  566.  
  567.     glEnable(GL_TEXTURE_2D);
  568.     glEnable(GL_TEXTURE_GEN_S);
  569.     glEnable(GL_TEXTURE_GEN_T);
  570.     glEnable(GL_TEXTURE_GEN_R);
  571.     glEnable(GL_TEXTURE_GEN_Q);
  572.     }
  573.  
  574.     if (mode == MoveObject || mode == MoveView) {
  575.     /* Have OpenGL compute the new transformation (simple but slow). */
  576.     glPushMatrix();
  577.     glLoadIdentity();
  578.     glRotatef(angle, axis[0], axis[1], axis[2]);
  579.     glMultMatrixf((GLfloat *) objectXform);
  580.     glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *) objectXform);
  581.     glPopMatrix();
  582.     }
  583.  
  584.     glPushMatrix();
  585.     glMultMatrixf((GLfloat *) objectXform);
  586.     (*drawObject)();
  587.     glPopMatrix();
  588.  
  589.     glDisable(GL_TEXTURE_2D);
  590.     glDisable(GL_TEXTURE_GEN_S);
  591.     glDisable(GL_TEXTURE_GEN_T);
  592.     glDisable(GL_TEXTURE_GEN_R);
  593.     glDisable(GL_TEXTURE_GEN_Q);
  594.  
  595.     if (zoomFactor > 1.0) {
  596.     glDisable(GL_DEPTH_TEST);
  597.     glCopyPixels(0, 0, winWidth/zoomFactor, winHeight/zoomFactor, GL_COLOR);
  598.     glEnable(GL_DEPTH_TEST);
  599.     }
  600.     glFlush();
  601.     glutSwapBuffers();
  602.     checkErrors();
  603. }
  604.  
  605. /*****************************************************************/
  606.  
  607. /* simple trackball-like motion control */
  608. GLboolean trackingMotion = GL_FALSE;
  609. float lastPos[3];
  610. int lastTime;
  611.  
  612. void
  613. ptov(int x, int y, int width, int height, float v[3])
  614. {
  615.     float d, a;
  616.  
  617.     /* project x,y onto a hemi-sphere centered within width, height */
  618.     v[0] = (2.0*x - width) / width;
  619.     v[1] = (height - 2.0*y) / height;
  620.     d = sqrt(v[0]*v[0] + v[1]*v[1]);
  621.     v[2] = cos((M_PI/2.0) * ((d < 1.0) ? d : 1.0));
  622.     a = 1.0 / sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
  623.     v[0] *= a;
  624.     v[1] *= a;
  625.     v[2] *= a;
  626. }
  627.  
  628. void
  629. startMotion(int x, int y, int but, int time)
  630. {
  631.     if (but == GLUT_LEFT_BUTTON) {
  632.     mode = MoveView;
  633.     } else if (but == GLUT_RIGHT_BUTTON) {
  634.     mode = MoveTexture;
  635.     } else {
  636.     return;
  637.     }
  638.  
  639.     trackingMotion = GL_TRUE;
  640.     redrawContinuously = GL_FALSE;
  641.     lastTime = time;
  642.     ptov(x, y, winWidth, winHeight, lastPos);
  643. }
  644.  
  645. /*ARGSUSED*/
  646. void
  647. stopMotion(int x, int y, int but, int time)
  648. {
  649.     if ((but == GLUT_LEFT_BUTTON && mode == MoveView) ||
  650.     (but == GLUT_RIGHT_BUTTON && mode == MoveTexture))
  651.     {
  652.     trackingMotion = GL_FALSE;
  653.     } else {
  654.     return;
  655.     }
  656.  
  657.     if (time == lastTime) {
  658.     redrawContinuously = GL_TRUE;
  659.     glutIdleFunc(display);
  660.     } else {
  661.     angle = 0.0;
  662.     redrawContinuously = GL_FALSE;
  663.     glutIdleFunc(0);
  664.     }
  665.     if (!redrawContinuously) {
  666.     mode = MoveNone;
  667.     }
  668. }
  669.  
  670. void
  671. trackMotion(int x, int y)
  672. {
  673.     if (trackingMotion) {
  674.     float curPos[3], dx, dy, dz;
  675.  
  676.     ptov(x, y, winWidth, winHeight, curPos);
  677.  
  678.     dx = curPos[0] - lastPos[0];
  679.     dy = curPos[1] - lastPos[1];
  680.     dz = curPos[2] - lastPos[2];
  681.     angle = 90.0 * sqrt(dx*dx + dy*dy + dz*dz);
  682.  
  683.     axis[0] = lastPos[1]*curPos[2] - lastPos[2]*curPos[1];
  684.     axis[1] = lastPos[2]*curPos[0] - lastPos[0]*curPos[2];
  685.     axis[2] = lastPos[0]*curPos[1] - lastPos[1]*curPos[0];
  686.  
  687.     lastTime = glutGet(GLUT_ELAPSED_TIME);
  688.     lastPos[0] = curPos[0];
  689.     lastPos[1] = curPos[1];
  690.     lastPos[2] = curPos[2];
  691.     glutPostRedisplay();
  692.     }
  693. }
  694.  
  695. /*****************************************************************/
  696.  
  697. void
  698. object(void)
  699. {
  700.     static int object;
  701.     object++; object %= 3;
  702.     switch (object) {
  703.       case 0:
  704.     drawObject = drawCube;
  705.     break;
  706.       case 1:
  707.     drawObject = drawDodecahedron;
  708.     break;
  709.       case 2:
  710.     drawObject = drawSphere;
  711.     break;
  712.       default:
  713.     break;
  714.     }
  715. }
  716.  
  717. void
  718. texture(void)
  719. {
  720.     static int texture;
  721.  
  722.     texture++; texture %= 3;
  723.     switch (texture) {
  724.       case 0:
  725.     loadTexture = NULL;
  726.     textureEnabled = GL_FALSE;
  727.     break;
  728.       case 1:
  729.     loadTexture = loadImageTexture;
  730.     (*loadTexture)();
  731.     textureEnabled = GL_TRUE;
  732.     break;
  733.       case 2:
  734.     loadTexture = loadSpotlightTexture;
  735.     (*loadTexture)();
  736.     textureEnabled = GL_TRUE;
  737.     break;
  738.       default:
  739.     break;
  740.     }
  741. }
  742.  
  743. void help(void) {
  744.     printf("'h'   - help\n");
  745.     printf("'l'   - toggle linear/nearest filter\n");
  746.     printf("'s'   - toggle projection frustum\n");
  747.     printf("'t'   - toggle projected texture\n");
  748.     printf("'o'   - toggle object\n");
  749.     printf("'z'   - increase zoom factor\n");
  750.     printf("'Z'   - decrease zoom factor\n");
  751.     printf("left mouse    - move view\n");
  752.     printf("right mouse   - move projection\n");
  753. }
  754.  
  755. /*ARGSUSED1*/
  756. void
  757. key(unsigned char key, int x, int y) {
  758.     switch(key) {
  759.     case '\033':
  760.     exit(EXIT_SUCCESS);
  761.     break;
  762.     case 'l':
  763.     linearFilter = !linearFilter;
  764.     (*loadTexture)();
  765.     break;
  766.     case 's':
  767.     showProjection = !showProjection;
  768.     break;
  769.     case 't':
  770.     texture();
  771.     break;
  772.     case 'o':
  773.     object();
  774.     break;
  775.     case 'z':
  776.     zoomFactor += 1.0;
  777.     glPixelZoom(zoomFactor, zoomFactor);
  778.     glViewport(0, 0, winWidth/zoomFactor, winHeight/zoomFactor);
  779.     break;
  780.     case 'Z':
  781.     zoomFactor -= 1.0;
  782.     if (zoomFactor < 1.0) zoomFactor = 1.0;
  783.     glPixelZoom(zoomFactor, zoomFactor);
  784.     glViewport(0, 0, winWidth/zoomFactor, winHeight/zoomFactor);
  785.     break;
  786.     case 'h': help(); break;
  787.     }
  788.     glutPostRedisplay();
  789. }
  790.  
  791. void
  792. mouse(int button, int state, int x, int y) {
  793.     if(state == GLUT_DOWN)
  794.     startMotion(x, y, button, glutGet(GLUT_ELAPSED_TIME));
  795.     else if (state == GLUT_UP)
  796.     stopMotion(x, y, button, glutGet(GLUT_ELAPSED_TIME));
  797.     glutPostRedisplay();
  798. }
  799.  
  800. void
  801. reshape(int w, int h)
  802. {
  803.     winWidth = w;
  804.     winHeight = h;
  805.     glViewport(0, 0, w/zoomFactor, h/zoomFactor);
  806. }
  807.  
  808. void
  809. usage(char **argv)
  810. {
  811.     fprintf(stderr, "usage: %s <image-filename>\n", argv[0]);
  812.     fprintf(stderr, "\n");
  813. }
  814.  
  815. int
  816. main(int argc, char **argv)
  817. {
  818.     glutInitWindowSize(512, 512);
  819.     glutInit(&argc, argv);
  820.     glutInitDisplayMode(GLUT_RGBA|GLUT_DEPTH|GLUT_DOUBLE);
  821.     (void)glutCreateWindow("projtex");
  822.     if (argc > 1) {
  823.     texFilename = argv[argc-1];
  824.     } else {
  825.     usage(argv);
  826.     exit(EXIT_FAILURE);
  827.     }
  828.     loadTexture = loadImageTexture;
  829.     drawObject = drawCube;
  830.     initialize();
  831.     glutDisplayFunc(display);
  832.     glutKeyboardFunc(key);
  833.     glutReshapeFunc(reshape);
  834.     glutMouseFunc(mouse);
  835.     glutMotionFunc(trackMotion);
  836.     glutMainLoop();
  837.     return 0;
  838. }
  839.